/**
	This file is part of Fighting Field.

	Fighting Field is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Fighting Field is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Fighting Field.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "InputManager.h"

#include "InputListener.h"

namespace FF
{
	InputManager::InputManager(Ogre::RenderWindow* window)
		: mInputManager(NULL), mKeyboard(NULL), mMouse(mMouse)
		, mActiveListener(NULL), mPressedButtons(0), mNbPressedKeys(0)
	{
		memset(mListeners, NULL, sizeof(InputListener*)*(size_t)InputLayer::Nb);

		for (unsigned int i = 0; i < 100; i++)
		{
			mPressedKeys[i] = false;
		}

		OIS::ParamList pl;
		size_t winHandle = 0;
		std::ostringstream winHandleStr;

		window->getCustomAttribute("WINDOW", &winHandle);
		winHandleStr << winHandle;

		pl.insert(std::make_pair("WINDOW", winHandleStr.str()));

		mInputManager = OIS::InputManager::createInputSystem(pl);

		mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
		mKeyboard->setEventCallback(this);

		mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
		mMouse->setEventCallback(this);

		windowResized(window);
	}

	InputManager::~InputManager()
	{
		if (mInputManager)
		{
			mInputManager->destroyInputObject(mKeyboard);
			mInputManager->destroyInputObject(mMouse);

			OIS::InputManager::destroyInputSystem(mInputManager);
			mInputManager = 0;
		}
	}

	void InputManager::Update(const Ogre::Real& dt)
	{
		UNUSED(dt)
		// capture input devices
		mKeyboard->capture();
		mMouse->capture();
	}

	void InputManager::RegisterListener(InputLayer::Val layer, InputListener* listener)
	{
		mListeners[layer] = listener;
	}

	void InputManager::UnregisterListener(InputLayer::Val layer, InputListener* listener)
	{
		if (mListeners[layer] == listener)
		{
			mListeners[layer] = NULL;
		}
	}
	
	bool InputManager::keyPressed(const OIS::KeyEvent& evt)
	{
		mPressedKeys[evt.key] = true;
		mNbPressedKeys++;

		if (mActiveListener)
		{
			return mActiveListener->OnKeyPressed(evt);
		}
		else
		{
			for (unsigned int i = 0; i < InputLayer::Nb; i++)
			{
				if (mListeners[i] && mListeners[i]->OnKeyPressed(evt))
				{
					mActiveListener = mListeners[i];
					return true;
				}
			}
		}

		return false;
	}

	bool InputManager::keyReleased(const OIS::KeyEvent& evt)
	{
		mPressedKeys[evt.key] = false;
		mNbPressedKeys--;

		if (mActiveListener)
		{
			mActiveListener->OnKeyReleased(evt);
			if (!mNbPressedKeys)
			{
				mActiveListener = NULL;
			}
		}

		return true;
	}

	bool InputManager::mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
	{
		mPressedButtons |= 1 << (unsigned int)(id);

		if (mActiveListener)
		{
			return mActiveListener->OnMousePressed(evt, id);
		}
		else
		{
			for (unsigned int i = 0; i < InputLayer::Nb; i++)
			{
				if (mListeners[i] && mListeners[i]->OnMousePressed(evt, id))
				{
					mActiveListener = mListeners[i];
					return true;
				}
			}
		}

		return true;
	}

	bool InputManager::mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
	{
		mPressedButtons &= ~(1 << (unsigned int)(id));

		if (mActiveListener)
		{
			mActiveListener->OnMouseReleased(evt, id);
			if (!mPressedButtons)
			{
				mActiveListener = NULL;
			}
		}

		return true;
	}

	bool InputManager::mouseMoved(const OIS::MouseEvent& evt)
	{
		if (mActiveListener && mActiveListener->OnMouseMoved(evt))
			return true;
		else
		{
			for (unsigned int i = 0; i < InputLayer::Nb; i++)
			{
				if (mListeners[i] && mListeners[i]->OnMouseMoved(evt))
					return true;
			}
		}

		return false;
	}

	void InputManager::windowResized(Ogre::RenderWindow* window)
	{
		const OIS::MouseState& ms = mMouse->getMouseState();
		ms.width = window->getWidth();
		ms.height = window->getHeight();
	}
}
